﻿using Elsa.Alterations.Extensions;
using Elsa.ApprovalFlow.Workflows;
using Elsa.Common;
using Elsa.EntityFrameworkCore.Extensions;
using Elsa.EntityFrameworkCore.Modules.Alterations;
using Elsa.EntityFrameworkCore.Modules.Management;
using Elsa.EntityFrameworkCore.Modules.Runtime;
using Elsa.Extensions;
using Elsa.Testing.Shared;
using Elsa.Workflows;
using Elsa.Workflows.Management;
using Elsa.Workflows.Runtime;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
using Xunit.Abstractions;

namespace Elsa.ApprovalFlow;

public abstract class WorkflowTestBase : IAsyncLifetime
{
    protected readonly IServiceProvider Services;
    protected readonly IWorkflowRunner WorkflowRunner;
    protected readonly IWorkflowRuntime WorkflowRuntime;
    protected readonly IWorkflowDefinitionService WorkflowDefinitionService;
    protected readonly IWorkflowMatcher WorkflowMatcher;
    protected readonly IWorkflowBuilderFactory WorkflowBuilderFactory;
    protected readonly IWorkflowInstanceStore WorkflowInstanceStore;
    protected readonly IWorkflowDefinitionStore WorkflowDefinitionStore;
    protected readonly IWorkflowDefinitionPublisher WorkflowDefinitionPublisher;
    protected readonly CapturingTextWriter TextWriter = new();
    protected readonly ITestOutputHelper Output;

    protected WorkflowTestBase(ITestOutputHelper helper)
    {
      
        Output = helper;
        Services = new TestApplicationBuilder(Output)            
            .WithCapturingTextWriter(TextWriter)
            .AddWorkflow<LeaveApprovalWorkflow>()
            .ConfigureElsa(x =>
            {
                var connString = "data source=127.0.0.1;database=elsademo;PORT=3306;uid=root;pwd=123456;charset=utf8mb4;Allow User Variables=True;Connect Timeout=90;Convert Zero Datetime=True;";
               
                x.UseAlterations(o =>
                {                    
                    o.UseEntityFrameworkCore(m =>
                    {
                        //m.UseSqlite("Data Source=:memory:");
                        m.UseMySql(connString);
                        m.RunMigrations = true;
                        m.ConfigureHostedServices();
                    });
                });
                
                x.UseWorkflowManagement(o =>
                {                 
                    o.UseEntityFrameworkCore(m =>
                    {
                        m.UseMySql(connString);
                        m.RunMigrations = true;
                        m.ConfigureHostedServices();
                        //m.UseSqlite("Data Source=:memory:");
                    });
                }).UseWorkflowRuntime(o =>
                {                    
                    o.UseEntityFrameworkCore(m =>
                    {
                        m.UseMySql(connString);
                        m.RunMigrations = true;
                        m.ConfigureHostedServices();
                        //m.UseSqlite("Data Source=:memory:");
                    });
                });
            })
            .AddActivitiesFrom<LeaveApprovalWorkflow>()           
            .Build();

        //Services.GetRequiredService<ElsaDbContext>().Database.Migrate();

        WorkflowRunner = Services.GetRequiredService<IWorkflowRunner>();
        WorkflowDefinitionService = Services.GetRequiredService<IWorkflowDefinitionService>();
        WorkflowBuilderFactory = Services.GetRequiredService<IWorkflowBuilderFactory>();
        WorkflowMatcher = Services.GetRequiredService<IWorkflowMatcher>();
        WorkflowRuntime = Services.GetRequiredService<IWorkflowRuntime>();
        WorkflowInstanceStore = Services.GetRequiredService<IWorkflowInstanceStore>();
        WorkflowDefinitionStore = Services.GetRequiredService<IWorkflowDefinitionStore>();
        WorkflowDefinitionPublisher = Services.GetRequiredService<IWorkflowDefinitionPublisher>();
    }

    public async Task InitializeAsync()
    {
        var tasks = Services.GetServices<IStartupTask>();
        var token = new CancellationTokenSource();
        foreach (var task in tasks)
        {
            await task.ExecuteAsync(token.Token);
        }
    }

    public Task DisposeAsync() => Task.CompletedTask;
}